package com.boyinet.imesh2json.netty.handler

import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.boyinet.imesh2json.common.CustomProtocol
import com.boyinet.imesh2json.netty.client.TransformClient
import com.boyinet.imesh2json.repo.DataMapRepository
import com.boyinet.imesh2json.repo.TemplateRepository
import com.boyinet.imesh2json.repo.TypeRepository
import com.boyinet.imesh2json.viewmodel.IndexViewModel
import io.netty.buffer.Unpooled
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.util.concurrent.DefaultEventExecutorGroup
import io.netty.util.concurrent.EventExecutorGroup
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

/**
 * @author lengchunyun
 */
@Sharable
@Component
class IMeshRequestHandler : SimpleChannelInboundHandler<List<CustomProtocol?>?>() {


    private val log: Logger = LoggerFactory.getLogger(IMeshRequestHandler::class.java)

    @Autowired
    lateinit var indexViewModel: IndexViewModel

    @Autowired
    lateinit var templateRepository: TemplateRepository

    @Autowired
    lateinit var dataMapRepository: DataMapRepository

    @Autowired
    lateinit var typeRepository: TypeRepository


    @Throws(Exception::class)
    override fun channelRead0(ctx: ChannelHandlerContext, msg: List<CustomProtocol?>?) {

        GROUP.submit {
            val id = indexViewModel.current.templateId.value

            val template = templateRepository.findById(id).get()

            val dataMaps = dataMapRepository.findDataMapsByTemplateIdEquals(id)

            val data: MutableList<JSONObject> = mutableListOf()

            msg?.let {
                msg.forEach {
                    val json = JSONObject()
                    json[template.sn] = it?.sn
                    if (template.originalValue) {
                        json[template.signalStrength] = it?.attributes?.signalStrength?.code
                        json[template.powerSource] = it?.attributes?.powerSource?.code
                        json[template.powerSupply] = it?.attributes?.powerSupply?.code
                        json[template.batteryPower] = it?.attributes?.batteryPower?.code
                        json[template.alarmStatus] = it?.attributes?.alarmStatus?.code
                    } else {
                        json[template.signalStrength] = it?.attributes?.signalStrength?.value
                        json[template.powerSource] = it?.attributes?.powerSource?.value
                        json[template.powerSupply] = it?.attributes?.powerSupply?.value
                        json[template.batteryPower] = it?.attributes?.batteryPower?.value
                        json[template.alarmStatus] = it?.attributes?.alarmStatus?.value
                    }

                    val fields = mutableListOf<JSONObject>()

                    it?.data?.forEach { d ->
                        val first = dataMaps.asSequence().filter { i ->
                            d.key == "${i.node}:${i.part}:${i.index}"
                        }.first()

                        fields.add(JSONObject().apply {
                            this[first.field] = d.value.value
                            this[template.decimalPlaces] = d.value.decimalPlaces
                            if (template.originalValue) {
                                this[template.unit] = d.value.unit
                                this[template.sensorType] = d.value.seniorType
                            } else {
                                this[template.unit] =
                                    typeRepository.findTypeByCodeEquals(d.value.unit.toString()).value
                                this[template.sensorType] =
                                    typeRepository.findTypeByCodeEquals(d.value.seniorType.toString()).value
                            }
                        })
                    }
                    json[template.fields] = fields
                    data.add(json)
                }
                val result = JSON.toJSONString(data, true)
                TransformClient.socketChannel?.writeAndFlush(
                    Unpooled.copiedBuffer(result.toByteArray())
                )
                println(result)
            }
        }
    }

    override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
        log.error(cause.message)
        ctx.channel().close()
    }

    companion object {
        private val GROUP: EventExecutorGroup = DefaultEventExecutorGroup(8)
    }
}